/*
 * codeGeneration.c
 *
 *  Created on: 1 Apr 2011
 *      Author: phthy08
 */
#include <stdio.h>
#include <string.h>
#include "memory.h"
#include "tree.h"
#include "code.h"
/* Body only for first time call*/
ll *front;
ll *first;
int i;
int ifcounter;
int cmpcounter;
int whilecounter;
int variables;
int mainvariables;
int HEAP_INDEX;
char *HEAP;
char *end_func;
reg *eax;
reg *ebx;
reg *ecx;
reg *edx;
reg *esi;
reg *edi;
reg *esp;
reg *ebp;

ll *codeBODY(BODY *body, SymbolTable *root){
	char *temp= NULL;
	char *space= NULL;
	front = NEW(ll);
	front->asc = NEW(asc);
	front->asc->kind= LABEL;
	front->asc->par.id = malloc(strlen(".global main")+1);
	front->previous = NULL;
	front->next = NULL;
	strcpy(front->asc->par.id,".global main");
	first = front;
	i=0;
	ifcounter=0;
	cmpcounter=0;
	whilecounter=0;
	variables=0;
	HEAP_INDEX=0;

	HEAP = malloc(strlen("heap"));
	strcpy(HEAP, "heap");
	temp= malloc(strlen("heap"));
	strcpy(temp,HEAP);
	space= malloc(strlen(". space ")+10);
	/* Creating form*/
	strcat(temp,":");
	sprintf(space,"\t.space %d", HEAP_SIZE);
	makeLABEL("form:");
	makeLABEL("\t.string \"%d\\n\"");
	makeLABEL(".data");
	makeLABEL("\t.align 4");
	makeLABEL(temp);
	makeLABEL(space);
	makeLABEL(".text");
	/*
	 * Creating registers
	 */
	eax = makeREG_REG();// register with ID = 0
	ebx = makeREG_REG();// register with ID = 1
	ecx = makeREG_REG();// register with ID = 2
	edx = makeREG_REG();// register with ID = 3
	esi = makeREG_REG();// register with ID = 4
	edi = makeREG_REG();// register with ID = 5
	esp = makeREG_REG();// register with ID = 6
	ebp = makeREG_REG();// register with ID = 7


	/* Initialize variables in main scope */
	makeCOUNT_VARS(body->decl_list, root);
	mainvariables = variables;
	variables = 0;
	/* Create functions */
	codeDECL_LIST_FUNC(body->decl_list);
	makeFUNC_LABEL("main:");
	/*STANDARD CALLE ACTIONS for main */
	variables = mainvariables;
	makeSAVE_REG();
	codeSTATEMENT_LIST(body->statement_list, root);
	makeRESTORE_REG();
	makeMOV_CONST(0,eax);
	makeRETURN();
	return first;
}

/*Creates new code for funcs*/
void codeDECL_LIST_FUNC(DECL_LIST *decl_list){
	int save = i;
	if(decl_list!=NULL){
		if(decl_list->declaration!=0){
			if(decl_list->declaration->kind == funcK){
				codeFUNC(decl_list->declaration->val.function);
				i = save;
			}
		}
		if(decl_list->decl_list!=0){
			codeDECL_LIST_FUNC(decl_list->decl_list);
		}
	}
}
void makeCOUNT_VARS(DECL_LIST *decl_list, SymbolTable *symboltable){
	if(decl_list!=0){
		if(decl_list->declaration->kind == varK){
			makeCOUNT_VAR(decl_list->declaration->val.var_decl_list, symboltable);
		}
		if(decl_list->decl_list!=0){
			makeCOUNT_VARS(decl_list->decl_list, symboltable);
		}
	}
}
void makeCOUNT_VAR(VAR_DECL_LIST *var_decl_list, SymbolTable *symboltable){
	SYMBOL *symbol;
	switch(var_decl_list->kind){
	case var_decl_listK:
		makeCOUNT_VAR(var_decl_list->var_decl_list, symboltable);
		variables++;
		symbol = getSymbol(symboltable, var_decl_list->var_type->id);
		symbol->pos = (-1)*(12+(variables*4));
		break;
	case var_decl_list_baseK:
		variables++;
		symbol = getSymbol(symboltable, var_decl_list->var_type->id);
		symbol->pos = (-1)*(12+(variables*4));
		break;
	}
}
void codeFUNC(FUNCTION *function){
	int funcvars = 0;
	variables = 0;
	makeCOUNT_VARS(function->body->decl_list, function->table);
	funcvars = variables;
	variables = 0;
	codeDECL_LIST_FUNC(function->body->decl_list);
	char *temp_end;
	if(function->head->par_decl_list!=0){
		int arguments = codeCOUNT_ARGS(function->head->par_decl_list->var_decl_list, 0);
		codeMAKE_POS(function->head->par_decl_list->var_decl_list, arguments, function->table);
	}
	char *label;
	label = malloc(strlen(function->head->id)+4);
	end_func = malloc(strlen(function->head->id)+strlen("end")+4);
	temp_end = malloc(strlen(function->head->id)+strlen("end")+4);
	sprintf(label,"%s:",function->head->id);
	sprintf(end_func,"%s_end",function->head->id);
	sprintf(temp_end,"%s_end:",function->head->id);
	makeFUNC_LABEL(label);
	if(function->body->decl_list!=0){
		makeCOUNT_VARS(function->body->decl_list, function->table);
	}
	makeSAVE_REG();
	codeSTATEMENT_LIST(function->body->statement_list, function->table);
	makeLABEL(temp_end);
	makeRESTORE_REG();
	variables = 0;
	makeRETURN();
}
void codeMAKE_POS(VAR_DECL_LIST *var_decl_list, int arguments, SymbolTable *symboltable){
	SYMBOL *symbol;
	symbol = getSymbol(symboltable, var_decl_list->var_type->id);
	symbol->pos = (8+(4*arguments));
	arguments--;
	if(arguments>0){
		codeMAKE_POS(var_decl_list->var_decl_list, arguments,symboltable);
	}
}

void codeSTATEMENT_LIST(STATEMENT_LIST *statement_list, SymbolTable *root){
	switch (statement_list->kind) {
	case statement_list_baseK:
		codeSTATEMENT(statement_list->statement, root);
		break;
	case statement_listK:
		codeSTATEMENT_LIST(statement_list->statement_list, root);
		if(statement_list->statement!=NULL){
			codeSTATEMENT(statement_list->statement, root);
		}
		break;
	}
}

void codeSTATEMENT(STATEMENT *statement, SymbolTable *root){
	char *label;
	char *label2;
	char *end;
	VARIABLE *variable;
	reg *reg1;
	reg *reg2;
	reg *reg3;
	OPT_ELSE *opt_else;
	switch(statement->kind){
	case returnK:
		reg1 = codeEXPRESSION(statement->val.return_expression, root);
		makeMOV(reg1,eax);
		makeJMP(end_func);
		break;
	case writeK:
		makePUSH(ecx);
		makePUSH(edx);
		reg1 = codeEXPRESSION(statement->val.write_expression, root);
		makePUSH(reg1);
		makeLABEL("\tpushl $form");
		makeCALL("printf");
		makePOP_ESP(2);
		makePOP(edx);
		makePOP(ecx);
		break;
	case allocateK:
		reg1= codeEXPRESSION(statement->val.allocateE.opt_length->expression,root);
		fprintf(stderr,"allocate size : %i \n",reg1->id);
		variable= statement->val.allocateE.variable;
		reg2= codeVARIABLE(variable,root);
		fprintf(stderr,"array variable reg \n");
		codeALLOCATE(reg1,reg2);
		fprintf(stderr,"after allocate h %i\n", HEAP_INDEX);
		break;
	case variableK:
		variable =statement->val.variableE.variable;
		reg1 = codeVARIABLE(variable, root);
		reg2 = codeEXPRESSION(statement->val.variableE.expression,root);
		makeMOV(reg2,reg1);
		break;
	case ifK:
		reg1 = codeEXPRESSION(statement->val.ifE.expression, root);
		label = malloc(strlen("else:")+4);
		sprintf(label,"else%i",ifcounter);
		end = malloc(strlen("end-if:")+4);
		sprintf(end,"end_if%i",ifcounter);
		makeCMP_CONST(1,reg1);
		if(statement->val.ifE.opt_else!=0){
			opt_else = statement->val.ifE.opt_else;
			makeJNE(label);
			codeSTATEMENT(statement->val.ifE.statement, root);
			makeJMP(end);
			strcat(label,":");
			makeLABEL(label);
			codeSTATEMENT(opt_else->statement, root);
		}else{
			makeJNE(end);
			codeSTATEMENT(statement->val.ifE.statement, root);
		}
		strcat(end,":");
		makeLABEL(end);
		ifcounter++;
		break;
	case whileK:
		label = malloc(strlen("while:")+4);
		sprintf(label,"while%i:",whilecounter);
		label2 = malloc(strlen("while")+4);
		sprintf(label2,"while%i",whilecounter);
		makeLABEL(label);
		end = malloc(strlen("end-while:")+4);
		sprintf(end,"end_while%i",whilecounter);
		reg1 = codeEXPRESSION(statement->val.whileE.expression, root);
		makeCMP_CONST(1,reg1);
		makeJNE(end);
		codeSTATEMENT(statement->val.whileE.statement, root);
		makeJMP(label2);
		strcat(end,":");
		makeLABEL(end);
		whilecounter++;
		break;
	case statementlistK:
		codeSTATEMENT_LIST(statement->val.statement_list, root);
		break;
	}
}/* Is copying the adress of the heap in the variable */
void codeALLOCATE(reg *reg_length,reg *reg_var){
	fprintf(stderr,"code allocate\n");
	char *get_adress=NULL;
	reg *reg_array_start=makeREG_REG();
	int array_start= HEAP_INDEX*4;
	makeMOV_CONST(array_start, reg_array_start);
	get_adress= malloc(strlen("\tmovl xxxx, %esi "));
	sprintf(get_adress,"\tmovl $%s, %%esi",HEAP);
	makeLABEL(get_adress);
	makeADD(reg_array_start,esi);
	makeMOV(esi, reg_var);
	HEAP_INDEX= HEAP_INDEX +reg_length->value;
}

reg *codeEXPRESSION(EXPRESSION *expression, SymbolTable *root){
	reg *reg1;
	reg *reg2;
	reg *reg3;
	reg *r;
	char *label;
	char *end;
	switch(expression->kind){
	case timesK:
		reg1 =codeEXPRESSION(expression->val.EXP_plus.left, root);
		reg2= codeEXPRESSION(expression->val.EXP_plus.right, root);
		reg3 = makeREG_REG();
		makeMUL(reg2,reg1);
		makeMOV(eax,reg3);
		return reg3;
		break;
	case divK:
		reg1 =codeEXPRESSION(expression->val.EXP_plus.left, root);
		reg2= codeEXPRESSION(expression->val.EXP_plus.right, root);
		makeMOV(reg1,eax);
		reg3= makeREG_REG();
		makeLABEL("\tcltd");
		makeDIV(reg2);
		makeMOV(eax, reg3);
		return reg3;
		break;
	case plusK:
		reg1 =codeEXPRESSION(expression->val.EXP_plus.left, root);
		reg2= codeEXPRESSION(expression->val.EXP_plus.right, root);
		reg3 = makeREG_REG();
		makeMOV(reg1,reg3);
		makeADD(reg2,reg3);
		return reg3;
		break;
	case minusK:
		reg1 =codeEXPRESSION(expression->val.EXP_plus.left, root);
		reg2= codeEXPRESSION(expression->val.EXP_plus.right, root);
		reg3 = makeREG_REG();
		makeMOV(reg1,reg3);
		makeSUB(reg2,reg3);
		return reg3;
		break;
	case orK:
		reg1 =codeEXPRESSION(expression->val.EXP_plus.left, root);
		reg2= codeEXPRESSION(expression->val.EXP_plus.right, root);
		reg3 = makeREG_REG();
		makeMOV(reg1,reg3);
		makeOR(reg2,reg3);
		return reg3;
		break;
	case andK:
		reg1 =codeEXPRESSION(expression->val.EXP_plus.left, root);
		reg2= codeEXPRESSION(expression->val.EXP_plus.right, root);
		reg3 = makeREG_REG();
		makeMOV(reg1,reg3);
		makeAND(reg2,reg3);
		return reg3;
		break;
	case leqK:
		reg1 =codeEXPRESSION(expression->val.EXP_plus.left, root);
		reg2= codeEXPRESSION(expression->val.EXP_plus.right, root);
		front->next = NEW(ll);
		r= NEW(reg);
		r->id= i;
		r->regid=NULL;
		i++;
		makeCMP(reg2,reg1);
		label = malloc(strlen("false:")+4);
		sprintf(label,"false%i",cmpcounter);
		end = malloc(strlen("cmpend:")+4);
		sprintf(end,"cmpend%i",cmpcounter);
		makeJG(label);
		makeMOV_CONST(1,r);
		makeJMP(end);
		strcat(label,":");
		makeLABEL(label);
		makeMOV_CONST(0,r);
		strcat(end,":");
		makeLABEL(end);
		cmpcounter++;
		return r;
		break;
	case geqK:
		reg1 =codeEXPRESSION(expression->val.EXP_plus.left, root);
		reg2= codeEXPRESSION(expression->val.EXP_plus.right, root);
		front->next = NEW(ll);
		r= NEW(reg);
		r->id= i;
		r->regid=NULL;
		i++;
		makeCMP(reg2,reg1);
		label = malloc(strlen("false:")+4);
		sprintf(label,"false%i",cmpcounter);
		end = malloc(strlen("cmpend:")+4);
		sprintf(end,"cmpend%i",cmpcounter);
		makeJL(label);
		makeMOV_CONST(1,r);
		makeJMP(end);
		strcat(label,":");
		makeLABEL(label);
		makeMOV_CONST(0,r);
		strcat(end,":");
		makeLABEL(end);
		cmpcounter++;
		return r;
		break;
	case leK:
		reg1 =codeEXPRESSION(expression->val.EXP_plus.left, root);
		reg2= codeEXPRESSION(expression->val.EXP_plus.right, root);
		front->next = NEW(ll);
		r= NEW(reg);
		r->id= i;
		r->regid=NULL;
		i++;
		makeCMP(reg2,reg1);
		label = malloc(strlen("false:")+4);
		sprintf(label,"false%i",cmpcounter);
		end = malloc(strlen("cmpend:")+4);
		sprintf(end,"cmpend%i",cmpcounter);
		makeJGE(label);
		makeMOV_CONST(1,r);
		makeJMP(end);
		strcat(label,":");
		makeLABEL(label);
		makeMOV_CONST(0,r);
		strcat(end,":");
		makeLABEL(end);
		cmpcounter++;
		return r;
		break;
	case grK:
		reg1 =codeEXPRESSION(expression->val.EXP_plus.left, root);
		reg2= codeEXPRESSION(expression->val.EXP_plus.right, root);
		front->next = NEW(ll);
		r= NEW(reg);
		r->id= i;
		r->regid=NULL;
		i++;
		makeCMP(reg2,reg1);
		label = malloc(strlen("false:")+4);
		sprintf(label,"false%i",cmpcounter);
		end = malloc(strlen("cmpend:")+4);
		sprintf(end,"cmpend%i",cmpcounter);
		makeJLE(label);
		makeMOV_CONST(1,r);
		makeJMP(end);
		strcat(label,":");
		makeLABEL(label);
		makeMOV_CONST(0,r);
		strcat(end,":");
		makeLABEL(end);
		cmpcounter++;
		return r;
		break;
	case eqK:
		reg1 =codeEXPRESSION(expression->val.EXP_plus.left, root);
		reg2= codeEXPRESSION(expression->val.EXP_plus.right, root);
		makeCMP(reg2,reg1);
		label = malloc(strlen("false:")+4);
		sprintf(label,"false%i",cmpcounter);
		end = malloc(strlen("cmpend:")+4);
		sprintf(end,"cmpend%i",cmpcounter);
		makeJNE(label);
		front->next = NEW(ll);
		r= NEW(reg);
		r->id= i;
		r->regid=NULL;
		i++;
		makeMOV_CONST(1,r);
		makeJMP(end);
		strcat(label,":");
		makeLABEL(label);
		makeMOV_CONST(0,r);
		strcat(end,":");
		makeLABEL(end);
		cmpcounter++;
		return r;
		break;
	case neqK:
		reg1 =codeEXPRESSION(expression->val.EXP_plus.left, root);
		reg2= codeEXPRESSION(expression->val.EXP_plus.right, root);
		makeCMP(reg2,reg1);
		label = malloc(strlen("true:")+4);
		sprintf(label,"true%i",cmpcounter);
		end = malloc(strlen("cmpend:")+4);
		sprintf(end,"cmpend%i",cmpcounter);
		makeJE(label);
		front->next = NEW(ll);
		r= NEW(reg);
		r->id= i;
		r->regid=NULL;
		i++;
		makeMOV_CONST(1,r);
		makeJMP(end);
		strcat(label,":");
		makeLABEL(label);
		makeMOV_CONST(0,r);
		strcat(end,":");
		makeLABEL(end);
		cmpcounter++;
		return r;
		break;
	case termK:
		return codeTERM(expression->val.term, root);
		break;
	}
	return NULL;
}
int codeCOUNT_ARGS(VAR_DECL_LIST *var_decl_list, int argcounter){
	switch(var_decl_list->kind){
	case var_decl_listK:
		argcounter++;
		return codeCOUNT_ARGS(var_decl_list->var_decl_list, argcounter);
		break;
	case var_decl_list_baseK:
		argcounter++;
		return argcounter;
		break;
	}
	return argcounter;
}
reg *codeTERM(TERM *term, SymbolTable *root){
	reg *r;
	reg *reg1 = NEW(reg);
	ACT_LIST *act_list;
	SYMBOL *symbol;
	FUNCTION *function;
	char *label;
	char *end;
	int argcounter = 0;
	int scope = 0;
	switch(term->kind){
	case term_varK:
		r = codeVARIABLE(term->val.variable, root);
		return r;
		break;
	case term_idK:
		symbol = getSymbol(root,term->val.term_idE.id);
		scope = codeSCOPE(root,term->val.term_idE.id,0);
		function = symbol->val.function;
		if(function->head->par_decl_list!=0){
			argcounter = codeCOUNT_ARGS(function->head->par_decl_list->var_decl_list, argcounter);
		}
		// argcounter now contains number of arguments
		if(argcounter>0){
			act_list = term->val.term_idE.act_list;
			codeEXP_LIST(act_list->exp_list, root);
		}

		if(scope>0){
			makePUSH(edx);
		}else{
			makePUSH(ebp);
		}
		makeCALL(term->val.term_idE.id);
		if(scope>0){
			makePOP(edx);
		}else{
			makePOP(ebp);
		}
		if(argcounter>0){
			makePOP_ESP(argcounter+1);
		}
		return eax;
		break;
	case term_expK:
		return codeEXPRESSION(term->val.expression, root);
		break;
	case term_notK:
		reg1 = codeTERM(term->val.term,root);
		label = malloc(strlen("false:")+4);
		sprintf(label,"false%i",cmpcounter);
		end = malloc(strlen("cmpend:")+4);
		sprintf(end,"cmpend%i",cmpcounter);
		makeCMP_CONST(1,reg1);
		makeJNE(label);
		makeMOV_CONST(0,reg1);
		makeJMP(end);
		strcat(label,":");
		makeLABEL(label);
		makeMOV_CONST(1,reg1);
		strcat(end,":");
		makeLABEL(end);
		cmpcounter++;
		return reg1;
		break;
	case term_act_expK:
		break;
	case term_numK:
		return makeREG(term->val.number);
		break;
	case term_trueK:
		return makeREG(1);
		break;
	case term_falseK:
		return makeREG(0);
		break;
	case term_nullK:
		break;
	}
	return NULL;
}
void codeEXP_LIST(EXP_LIST *exp_list, SymbolTable *symboltable){
	reg *reg1;
	reg1 = codeEXPRESSION(exp_list->expression,symboltable);
	makePUSH(reg1);//
	if(exp_list->kind == exp_listK){
		codeEXP_LIST(exp_list->exp_list, symboltable);
	}
}

reg *codeVARIABLE(VARIABLE *variable, SymbolTable *root){
	SYMBOL *symbol;
	char *label;
	reg *r;
	reg *reg1;
	reg *reg2;
	int scope;
	int position;
	r= NEW(reg);
	r->id= -42;
	switch(variable->kind){
	case var_idK:
		scope = codeSCOPE(root,variable->val.id,0);
		symbol = getSymbol(root, variable->val.id);
		position = symbol->pos;

		if(scope>0){
			makeMOVEPOS(ebp,edx,8,0);
			if(scope>1){
				int j;
				for(j = 0; j < scope-1; j++){
					makeMOVEPOS(edx,edx,8,0);
				}
				label = malloc(strlen("(%edx)")+4);
				sprintf(label,"%i",position);
				strcat(label,"(%edx)");
				r->regid=label;
				return r;
			}else{
				label = malloc(strlen("(%edx)")+4);
				sprintf(label,"%i",position);
				strcat(label,"(%edx)");
				r->regid=label;
				return r;
			}
		}else{
			label = malloc(strlen("(%ebp)")+4);
			sprintf(label,"%i",position);
			strcat(label,"(%ebp)");
			r->regid=label;
			return r;
		}
		return r;
		break;
	case var_expK:
		reg1= codeEXPRESSION(variable->val.var_expE.expression,root);
		reg2=codeVARIABLE(variable->val.var_expE.variable,root);
		makeMOV(reg2, esi);
		label = malloc(strlen("(%esi)")+4);
		sprintf(label,"%i",reg1->value*4 );
		strcat(label,"(%esi)");
		r->regid=label;
		return r;
		break;
	case var_dotK:
		break;
	}
	return NULL;
}
int codeSCOPE(SymbolTable *symboltable, char *name, int scope){
	int index = Hash(name);
	if (symboltable->table[index] != NULL) {
		/* if a symbol exists */
		SYMBOL *symbol = symboltable->table[index];
		while (strcmp(symbol->name, name) != 0 && symbol->next != NULL) {
			symbol = symbol->next;
		}
		if(strcmp(symbol->name, name) == 0){
			return scope;
		}
		if (strcmp(symbol->name, name) != 0){
			if (symboltable->next != NULL){
				scope++;
				scope = codeSCOPE(symboltable->next, name, scope);
				return scope;
			} else {
				return -1;
			}
		}
	} else {
		/* if there is nothing in the bucket */
		if (symboltable->next != NULL) {
			scope++;
			scope = codeSCOPE(symboltable->next, name, scope);
			return scope;
		} else {
			return -1;
		}
	}
	return scope;
}
void makeLABEL(char *label){
	ll *llLABEL = NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= LABEL;
	llLABEL->asc->par.id = malloc(strlen(label)+1);
	strcpy(llLABEL->asc->par.id, label);
	llLABEL->previous= front;
	llLABEL->next= NULL;
	front->next= llLABEL;
	front = llLABEL;
}
void makeFUNC_LABEL(char *label){
	ll *llLABEL = NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= FUNCLABEL;
	llLABEL->asc->par.id = malloc(strlen(label)+1);
	strcpy(llLABEL->asc->par.id, label);
	llLABEL->previous= front;
	llLABEL->next= NULL;
	front->next= llLABEL;
	front = llLABEL;
}

void makeRETURN(){
	ll *llLABEL = NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= RETURN;
	llLABEL->asc->par.id = malloc(strlen("\tret")+1);
	strcpy(llLABEL->asc->par.id, "\tret");
	llLABEL->previous= front;
	llLABEL->next= NULL;
	front->next= llLABEL;
	front = llLABEL;
}
void makePUSH(reg *arg){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= PUSH;
	llLABEL->asc->par.arguments.first= arg;
	llLABEL->asc->par.arguments.second= NULL;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makePUSH_CONST(int value){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= PUSH_CONST;
	llLABEL->asc->par.arguments_const.first= value;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeMOVEPOS(reg *arg1, reg *arg2, int pos1, int pos2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= MOVEPOS;
	llLABEL->asc->par.regs.first = arg1;
	llLABEL->asc->par.regs.second = arg2;
	llLABEL->asc->par.regs.pos1 = pos1;
	llLABEL->asc->par.regs.pos2 = pos2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeMOV(reg *arg1, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= MOV;
	llLABEL->asc->par.arguments.first = arg1;
	llLABEL->asc->par.arguments.second = arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makeMOV_CONST(int arg1, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= MOV_CONST;
	llLABEL->asc->par.arguments_const.first = arg1;
	llLABEL->asc->par.arguments_const.second = arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makePOP(reg *arg){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= POP;
	llLABEL->asc->par.arguments.first= arg;
	llLABEL->asc->par.arguments.second= NULL;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makeADD(reg *arg1, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= ADD;
	llLABEL->asc->par.arguments.first= arg1;
	llLABEL->asc->par.arguments.second= arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makeADD_CONST(int value, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= ADD_CONST;
	llLABEL->asc->par.arguments_const.first= value;
	llLABEL->asc->par.arguments_const.second= arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makeSUB(reg *arg1, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= SUB;
	llLABEL->asc->par.arguments.first= arg1;
	llLABEL->asc->par.arguments.second= arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makeSUB_CONST(int value, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= SUB_CONST;
	llLABEL->asc->par.arguments_const.first= value;
	llLABEL->asc->par.arguments_const.second= arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeDIV(reg *arg1){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= DIV;
	llLABEL->asc->par.arguments.first= arg1;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makeDIV_CONST(int value, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= DIV_CONST;
	llLABEL->asc->par.arguments_const.first= value;
	llLABEL->asc->par.arguments_const.second= arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makeMUL(reg *arg1, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= MUL;
	llLABEL->asc->par.arguments.first= arg1;
	llLABEL->asc->par.arguments.second= arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makeMUL_CONST(int value, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= MUL_CONST;
	llLABEL->asc->par.arguments_const.first= value;
	llLABEL->asc->par.arguments_const.second= arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makeAND(reg *arg1, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= AND;
	llLABEL->asc->par.arguments.first= arg1;
	llLABEL->asc->par.arguments.second= arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makeOR(reg *arg1, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= OR;
	llLABEL->asc->par.arguments.first= arg1;
	llLABEL->asc->par.arguments.second= arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makeNEG(reg *arg){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= NEG;
	llLABEL->asc->par.arguments.first= arg;
	llLABEL->asc->par.arguments.second= NULL;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makeCMP_CONST(int value, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= CMP_CONST;
	llLABEL->asc->par.arguments_const.first= value;
	llLABEL->asc->par.arguments_const.second=arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeCMP(reg *arg1, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= CMP;
	llLABEL->asc->par.arguments.first= arg1;
	llLABEL->asc->par.arguments.second=arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makeJA(reg *arg1, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind=JA;
	llLABEL->asc->par.arguments.first= arg1;
	llLABEL->asc->par.arguments.second= arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}

void makeJAE(reg *arg1, reg *arg2){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= JMP;
	llLABEL->asc->par.arguments.first= arg1;
	llLABEL->asc->par.arguments.second= arg2;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeJMP(char *label){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= JMP;
	llLABEL->asc->par.id = malloc(strlen(label)+1);
	strcpy(llLABEL->asc->par.id, label);
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeJNE(char *label){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= JNE;
	llLABEL->asc->par.id = malloc(strlen(label)+1);
	strcpy(llLABEL->asc->par.id, label);
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeJE(char *label){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= JE;
	llLABEL->asc->par.id = malloc(strlen(label)+1);
	strcpy(llLABEL->asc->par.id, label);
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeJG(char *label){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= JG;
	llLABEL->asc->par.id = malloc(strlen(label)+1);
	strcpy(llLABEL->asc->par.id, label);
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeJGE(char *label){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= JGE;
	llLABEL->asc->par.id = malloc(strlen(label)+1);
	strcpy(llLABEL->asc->par.id, label);
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeJLE(char *label){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= JLE;
	llLABEL->asc->par.id = malloc(strlen(label)+1);
	strcpy(llLABEL->asc->par.id, label);
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeJL(char *label){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= JL;
	llLABEL->asc->par.id = malloc(strlen(label)+1);
	strcpy(llLABEL->asc->par.id, label);
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeCALL(char *call){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= CALL;
	llLABEL->asc->par.id = malloc(strlen(call));
	strcpy(llLABEL->asc->par.id, call);
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeTEMP_ALLOC(){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= ALLOC;
	llLABEL->asc->par.arguments_const.first= variables;
	llLABEL->asc->par.arguments_const.second= NULL;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeTEMP_DEALLOC(){
	ll *llLABEL= NEW(ll);
	llLABEL->asc = NEW(asc);
	llLABEL->asc->kind= DEALLOC;
	llLABEL->asc->par.arguments_const.first= 0;
	llLABEL->asc->par.arguments_const.second= NULL;
	front->next=llLABEL;
	llLABEL->previous= front;
	front = llLABEL;
}
void makeSAVE_REG(){
	makePUSH(ebp);
	makeMOV(esp,edx);
	makeMOV(edx,ebp);
	makePUSH(ebx);
	makePUSH(esi);
	makePUSH(edi);
	/* Allocate space for variables and temporaries */
	makeTEMP_ALLOC();
}

void makeRESTORE_REG(){
	/* Deallocate space for temporaries and variables */
	makeTEMP_DEALLOC();
	makePOP(edi);
	makePOP(esi);
	makePOP(ebx);
	makeMOV(ebp,edx);
	makeMOV(edx,esp);
	makePOP(ebp);
}

reg *makeREG(int value){
	reg *r= NEW(reg);
	r->id= i;
	r->regid=NULL;
	i++;
	r->value=value;
	makeMOV_CONST(value, r);
	return r;
}

reg *makeREG_REG(){
	reg *r= NEW(reg);
	r->id= i;
	r->regid=NULL;
	i++;
	r->value=0;
	return r;
}

reg *makeREG_ID(int i, char *name){
	reg *r= NEW(reg);
	r->id= i;
	r->regid = malloc(strlen(name));
	strcpy(r->regid, name);
	r->value=0;
	return r;
}

void makePOP_ESP(int amount){
	makeADD_CONST(amount*4, esp);
}

